package com.mes.spc.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mes.spc.util.SpcCalUtil;
import com.yy.base.common.dao.Dao;

/**
 * 控制图查看
 */
@Service
public class EmesqSpcChartViewService {
    @Autowired
    private Dao dao;

    /**
     * 计算XR图的相关值 包括 平均值的UCL CL LCL及方差的UCL CL LCL
     * @param avgNums
     * @param rNums
     * @param sampleSize
     */
    public Map<String,Double> calXRChartData(double[] avgNums,double[] rNums,int sampleSize,double LSL,double USL,double target){
        //基础数据
        Map<String,Double> data = new HashMap<String,Double>();
        if(sampleSize<2)return data;
        double CL_X = SpcCalUtil.avage(avgNums);//样板平均值
        double CL_R = SpcCalUtil.avage(rNums);//极差平均值
        //计算均值
        double UCL_X = SpcCalUtil.ZeroFormat(CL_X+SpcCalUtil.A2ConstantNum[sampleSize-2]*CL_R,3);
        double LCL_X = SpcCalUtil.ZeroFormat(CL_X-SpcCalUtil.A2ConstantNum[sampleSize-2]*CL_R,3);
        //计算极差
        double UCL_R = SpcCalUtil.ZeroFormat(CL_R*SpcCalUtil.D4ConstantNum[sampleSize-2],3);
        double LCL_R = SpcCalUtil.ZeroFormat(CL_R*SpcCalUtil.D3ConstantNum[sampleSize-2],3);
        data.put("CL_X",CL_X);
        data.put("UCL_X",UCL_X);
        data.put("LCL_X",LCL_X);
        data.put("CL_R",CL_R);
        data.put("UCL_R",UCL_R);
        data.put("LCL_R",LCL_R);
        data.put("LSL",LSL);
        data.put("USL",USL);
        data.put("Target",target);
        data.put("maxArrayX",SpcCalUtil.getYMaxNum(USL,new double[]{SpcCalUtil.max(avgNums),UCL_X}));
        data.put("minArrayX",SpcCalUtil.getYMinNum(LSL,new double[]{SpcCalUtil.min(avgNums),LCL_X}));
        data.put("maxArrayR",SpcCalUtil.max(new double[]{SpcCalUtil.max(rNums),UCL_R}));
        data.put("minArrayR",SpcCalUtil.min(new double[]{SpcCalUtil.min(rNums),LCL_R}));
        return data;
    }

    /**
     * 计算XS相关值
     * @param avgNums
     * @param avgRArray
     * @param stdevArray
     * @param sampleSize
     * @return
     */
    public Map<String,Double> calXSChartData(double[] avgNums,double[] avgRArray,double[] stdevArray,int sampleSize,double LSL,double USL,double target){
        Map<String,Double> data = new HashMap<String,Double>();
        if(sampleSize<2)return data;
        double CL_X = SpcCalUtil.avage(avgNums);//样板平均值
        double CL_S = SpcCalUtil.avage(stdevArray);//标准差平均值
        double CL_R = SpcCalUtil.avage(avgRArray);//极差平均值
        //计算均值
        double UCL_X = CL_X+SpcCalUtil.A2ConstantNum[sampleSize-2]*CL_R;
        double LCL_X = CL_X-SpcCalUtil.A2ConstantNum[sampleSize-2]*CL_R;
        //计算标准差
        double UCL_S = CL_S*SpcCalUtil.B4ConstantNum[sampleSize-2];
        double LCL_S = CL_S*SpcCalUtil.B3ConstantNum[sampleSize-2];
        data.put("CL_X",CL_X);
        data.put("UCL_X",UCL_X);
        data.put("LCL_X",LCL_X);
        data.put("CL_S",CL_S);
        data.put("UCL_S",UCL_S);
        data.put("LCL_S",LCL_S);
        data.put("LSL",LSL);
        data.put("USL",USL);
        data.put("Target",target);
        data.put("maxArrayX",SpcCalUtil.getYMaxNum(USL,new double[]{SpcCalUtil.max(avgNums),UCL_X}));
        data.put("minArrayX",SpcCalUtil.getYMinNum(LSL,new double[]{SpcCalUtil.min(avgNums),LCL_X}));
        data.put("maxArrayS",SpcCalUtil.max(new double[]{SpcCalUtil.max(stdevArray),UCL_S}));
        data.put("minArrayS",SpcCalUtil.min(new double[]{SpcCalUtil.min(stdevArray),LCL_S}));
        return data;
    }

    /**
     * 计算IMR图相关数据
     * @param avgNums
     * @param rNums
     * @param sampleSize
     * @return
     */
    public Map<String,Double> calIMRChartData(double[] avgNums,double[] rNums,int sampleSize,Double LSL,Double USL,Double target){
        // 计算移动极差的标准差 没有为过程标准差 σ 指定历史值，Minitab 将使用指定的方法根据数据估计 σ。
        double sumJc = 0d;//移动极差的和
        for(int i = 1;i<avgNums.length;i++){
            sumJc+=Math.max(avgNums[i],avgNums[i-1])-Math.min(avgNums[i],avgNums[i-1]);
        }
        int w = 2;//移动极差的长度。默认值为 2。
        double avgSumJc = sumJc/((avgNums.length-w+1)*1d);//移动极差平均值
        double stdev = avgSumJc/SpcCalUtil.D2ConstantNum[w-2];

        Map<String,Double> data = new HashMap<String,Double>();
        double CL_X = SpcCalUtil.avage(avgNums);//样板平均值
        double CL_R = avgSumJc;//移动极差平均值
        //计算均值
        double UCL_X = CL_X+stdev*3;
        double LCL_X = CL_X-stdev*3;
        //计算极差
        double UCL_R = CL_R+3*stdev*SpcCalUtil.d3ConstantNum[w-2];
        double LCL_R = CL_R-3*stdev*SpcCalUtil.d3ConstantNum[w-2];
        if(LCL_R<0)LCL_R=0d;
        data.put("CL_X",CL_X);
        data.put("UCL_X",UCL_X);
        data.put("LCL_X",LCL_X);
        data.put("CL_R",CL_R);
        data.put("UCL_R",UCL_R);
        data.put("LCL_R",LCL_R);
        if(USL!=null)
        data.put("USL",USL);
        if(LSL!=null)
            data.put("LSL",LSL);
        if(target!=null)
            data.put("target",target);
        data.put("maxArrayX",SpcCalUtil.getYMaxNum(USL,new double[]{SpcCalUtil.max(avgNums),UCL_X}));
        data.put("minArrayX",SpcCalUtil.getYMinNum(LSL,new double[]{SpcCalUtil.min(avgNums),LCL_X}));
        data.put("maxArrayR",SpcCalUtil.max(new double[]{SpcCalUtil.max(rNums),UCL_R}));
        data.put("minArrayR",SpcCalUtil.min(new double[]{SpcCalUtil.min(rNums),LCL_R}));
        return data;
    }

    /**
     * CPK分析图
     * @param arrData
     * @param avgNums
     * @param rNums
     * @param sampleSize
     * @param USL
     * @param LSL
     * @return
     */
    public Map<String,Object> cpkAnalysis(double[] arrData, double[] avgNums, double[] rNums, int sampleSize, double USL, double LSL,double target){
        boolean imrFlag = false;
        if(sampleSize==1){
            sampleSize=2;
            imrFlag=true;
        }//样本为1时默认取首个常数
        double Avage = SpcCalUtil.avage(arrData);//样本平均
        double Avagejj = SpcCalUtil.avage(rNums);//极差平均
        double StDev = SpcCalUtil.stDev(arrData);//整体标准差
        double StDev_zn = Avagejj/SpcCalUtil.D2ConstantNum[sampleSize-2];//组内标准差
        if(imrFlag){
            Avagejj = SpcCalUtil.sum(rNums)/(rNums.length-1);
            StDev_zn = Avagejj/SpcCalUtil.D2ConstantNum[sampleSize-2];;
        }
        double StDev_zn3p = (Avage+3*StDev_zn);//正三倍标准差
        double StDev_zn3n = (Avage-3*StDev_zn);//负三倍标准差
        double Pp = SpcCalUtil.cp(USL, LSL,StDev);//工序能力（整体）
        double PpkU = SpcCalUtil.cpkU(USL, Avage, StDev);//工序能力（整体）
        double PpkL = SpcCalUtil.cpkL(LSL, Avage, StDev);//工序能力（整体）
        double Cp = SpcCalUtil.cp(USL, LSL,StDev_zn);//工序能力（组内）
        double CpkU = SpcCalUtil.cpkU(USL, Avage,StDev_zn);//工序能力（组内）
        double CpkL = SpcCalUtil.cpkL(LSL, Avage,StDev_zn);//工序能力（组内）
        double Ca = 0;
        if(USL!=LSL)
        Ca = (Avage-(USL + LSL)/2)/((USL - LSL)/2);



        //正态分布图
        double maxNum = SpcCalUtil.max(arrData);
        double minNum = SpcCalUtil.min(arrData);
        double jkNum = maxNum-minNum;
//        double target = (USL + LSL)/2f;//目标值
        int groupSize = (int)Math.round(Math.sqrt(arrData.length));//分组数
        double groupGap = (double)(Math.ceil(jkNum/groupSize*1000d))/1000d;
        groupSize = groupSize+2;


        int tempi = 0;
        List<Double> tempList = new ArrayList<Double>();
        double tempv = Math.floor(minNum)-groupGap;
        boolean t_u = false;
        boolean t_t = false;
        boolean t_l = false;
        do{
        	if(SpcCalUtil.ZeroFormat(tempv,2)==USL){
        		t_u = true;
        	}
			if(SpcCalUtil.ZeroFormat(tempv,2)==target){
				t_t = true;
			}
			if(SpcCalUtil.ZeroFormat(tempv,2)==LSL){
				t_l = true;
			}
			if(tempv>0){
				tempList.add(tempv);
			}
            tempi++;
            tempv = tempv+groupGap;
        }while (tempv<((USL!=SpcCalUtil.ErrNum?USL:maxNum) +groupGap*2));
        if(!t_u)tempList.add(USL);
        if(!t_t)tempList.add(target);
        if(!t_l)tempList.add(LSL);
        double[] xArrays = new double[tempList.size()];//横轴坐标
        for(int i =0;i<xArrays.length;i++){
            xArrays[i]=SpcCalUtil.ZeroFormat(tempList.get(i),2);
        }
//        double[] xArrays = new double[groupSize];//横轴坐标
//        double tempNum = minNum-groupGap;
//        for(int i = 1;i<groupSize-1;i++){
//            xArrays[i]=tempNum+groupGap*i;
//        }
//        xArrays[0] = xArrays[1]-groupGap;
//        xArrays[groupSize-1] = xArrays[groupSize-2]+groupGap;
        int[] frequencyArray = SpcCalUtil.frequency(arrData,xArrays);//正态柱状数量

//        List<Double> newZtArrays = new ArrayList<>();
//        List<Double> newZtAllArrays = new ArrayList<>();
        double[] ztArrays = new double[xArrays.length];//正态分布点值 组内
        double[] ztAllArrays = new double[xArrays.length];//正态分布点值 整体
        for(int i =0;i<xArrays.length;i++){
            if(SpcCalUtil.getNormalValue(xArrays[i],Avage,StDev_zn)!=0&&SpcCalUtil.getNormalValue(xArrays[i],Avage,StDev)!=0) {
                ztArrays[i] = SpcCalUtil.getNormalValue(xArrays[i], Avage, StDev_zn);
                ztAllArrays[i] = SpcCalUtil.getNormalValue(xArrays[i], Avage, StDev);
//                newZtArrays.add(SpcCalUtil.getNormalValue(xArrays[i], Avage, StDev_zn));
//                newZtAllArrays.add(SpcCalUtil.getNormalValue(xArrays[i], Avage, StDev));
            }
        }

//        ztArrays = ArrayUtils.toPrimitive(newZtArrays.toArray(new Double[newZtArrays.size()]));
//        ztAllArrays = ArrayUtils.toPrimitive(newZtAllArrays.toArray(new Double[newZtAllArrays.size()]));
        double UpBdRate_E = SpcCalUtil.ZeroFormat((1-SpcCalUtil.GetP((USL - Avage) / StDev_zn))*1000000,3);
        double LowBdRate_E = SpcCalUtil.ZeroFormat(SpcCalUtil.GetP((LSL - Avage) / StDev_zn)*1000000,3);
        double SumBdRate_E = SpcCalUtil.ZeroFormat(UpBdRate_E + LowBdRate_E,3);

        double UpBdRate_G = SpcCalUtil.ZeroFormat((1-SpcCalUtil.GetP((USL - Avage) / StDev))*1000000,3);
        double LowBdRate_G = SpcCalUtil.ZeroFormat(SpcCalUtil.GetP((LSL - Avage) / StDev)*1000000,3);
        double SumBdRate_G = SpcCalUtil.ZeroFormat(UpBdRate_G + LowBdRate_G,3);

        int gtUCLSize = 0;
        int ltLCLSize = 0;
        if(maxNum> USL){
            for(double i :arrData){
                if(i> USL)gtUCLSize++;
            }
        }
        if(minNum< LSL){
            for(double i :arrData){
                if(i< LSL)ltLCLSize++;
            }
        }
        double UpBdRate = SpcCalUtil.ZeroFormat(gtUCLSize*1000000d/arrData.length,3);
        double LowBdRate = SpcCalUtil.ZeroFormat(ltLCLSize*1000000d/arrData.length,3);
        double SumBdRate = SpcCalUtil.ZeroFormat(UpBdRate + LowBdRate,3);

        //返回
        Map<String,Object> data = new HashMap<String,Object>();
        data.put("ztArrays",ztArrays);
        data.put("frequencyArray",frequencyArray);
        data.put("frequencyMax",SpcCalUtil.maxInt(frequencyArray));
        data.put("xArrays",xArrays);
        data.put("ztAllArrays",ztAllArrays);
        data.put("sampleSize",arrData.length);
        data.put("Avage",SpcCalUtil.ZeroFormat(Avage,3));
        data.put("maxNum",SpcCalUtil.ZeroFormat(maxNum,3));
        data.put("minNum",SpcCalUtil.ZeroFormat(minNum,3));
        data.put("sampleGroupSize",imrFlag?1:sampleSize);

        data.put("USL", USL!=SpcCalUtil.ErrNum?USL:"N/A");
        data.put("LSL", LSL!=SpcCalUtil.ErrNum?LSL:"N/A");
        data.put("target",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":target);
        data.put("StDev_zn",SpcCalUtil.ZeroFormat(StDev_zn,3));
        data.put("StDev",SpcCalUtil.ZeroFormat(StDev,3));
        data.put("StDev_zn3n",SpcCalUtil.ZeroFormat(StDev_zn3n,3));
        data.put("StDev_zn3p",SpcCalUtil.ZeroFormat(StDev_zn3p,3));
        data.put("Cp",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(Cp,3));
        data.put("Cpk",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(SpcCalUtil.cpk(CpkU, CpkL),3));
        data.put("CpkL",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(CpkL,3));
        data.put("CpkU",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(CpkU,3));
        data.put("Pp",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(Pp,3));
        data.put("Ppk",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(SpcCalUtil.cpk(PpkU, PpkL),3));
        data.put("PpkL",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(PpkL,3));
        data.put("PpkU",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(PpkU,3));
        data.put("Ca",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(Ca,3));
        data.put("UpBdRate_E",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":UpBdRate_E);
        data.put("LowBdRate_E",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":LowBdRate_E);
        data.put("SumBdRate_E",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SumBdRate_E);
        data.put("UpBdRate_G",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":UpBdRate_G);
        data.put("LowBdRate_G",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":LowBdRate_G);
        data.put("SumBdRate_G",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SumBdRate_G);
        data.put("UpBdRate",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":UpBdRate);
        data.put("LowBdRate",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":LowBdRate);
        data.put("SumBdRate",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SumBdRate);
        return data;
    }
    
    /**
     * CPK分析图
     * @param arrData
     * @param avgNums
     * @param rNums
     * @param sampleSize
     * @param USL
     * @param LSL
     * @return
     */
    public Map<String,Object> cpkAnalysis(double[] arrData, double[] avgNums, double[] rNums, double[] stdevArray, int sampleSize, double USL, double LSL,double target){
        boolean imrFlag = false;
        if(sampleSize==1){
            sampleSize=2;
            imrFlag=true;
        }//样本为1时默认取首个常数
        double Avage = SpcCalUtil.avage(arrData);//样本平均
        double Avagejj = SpcCalUtil.avage(rNums);//极差平均
        double StDev = SpcCalUtil.stDev(arrData);//整体标准差
        double StDev_zn = Avagejj/SpcCalUtil.D2ConstantNum[sampleSize-2];//组内标准差
        if(imrFlag){
            Avagejj = SpcCalUtil.sum(rNums)/(rNums.length-1);
            StDev_zn = Avagejj/SpcCalUtil.D2ConstantNum[sampleSize-2];;
        }else{
        	//计算合并标准差 minitab计算方法
            double stdSum = 0;
            for(double std:stdevArray){
            	stdSum += (sampleSize-1)*Math.pow(std, 2);
            }
            StDev_zn = Math.sqrt(stdSum/(stdevArray.length*sampleSize-stdevArray.length));
        }
        double StDev_zn3p = (Avage+3*StDev_zn);//正三倍标准差
        double StDev_zn3n = (Avage-3*StDev_zn);//负三倍标准差
        double Pp = SpcCalUtil.cp(USL, LSL,StDev);//工序能力（整体）
        double PpkU = SpcCalUtil.cpkU(USL, Avage, StDev);//工序能力（整体）
        double PpkL = SpcCalUtil.cpkL(LSL, Avage, StDev);//工序能力（整体）
        double Cp = SpcCalUtil.cp(USL, LSL,StDev_zn);//工序能力（组内）
        double CpkU = SpcCalUtil.cpkU(USL, Avage,StDev_zn);//工序能力（组内）
        double CpkL = SpcCalUtil.cpkL(LSL, Avage,StDev_zn);//工序能力（组内）
        double Ca = 0;
        if(USL!=LSL)
        Ca = (Avage-(USL + LSL)/2)/((USL - LSL)/2);



        //正态分布图
        double maxNum = SpcCalUtil.max(arrData);
        double minNum = SpcCalUtil.min(arrData);
        double jkNum = maxNum-minNum;
//        double target = (USL + LSL)/2f;//目标值
        int groupSize = (int)Math.round(Math.sqrt(arrData.length));//分组数
        double groupGap = (double)(Math.ceil(jkNum/groupSize*1000d))/1000d;
        groupSize = groupSize+2;


        int tempi = 0;
        List<Double> tempList = new ArrayList<Double>();
        double tempv = Math.floor(minNum)-groupGap;
        boolean t_u = false;
        boolean t_t = false;
        boolean t_l = false;
        do{
        	if(SpcCalUtil.ZeroFormat(tempv,2)==USL){
        		t_u = true;
        	}
			if(SpcCalUtil.ZeroFormat(tempv,2)==target){
				t_t = true;
			}
			if(SpcCalUtil.ZeroFormat(tempv,2)==LSL){
				t_l = true;
			}
			if(tempv>0){
				tempList.add(tempv);
			}
            tempi++;
            tempv = tempv+groupGap;
        }while (tempv<((USL!=SpcCalUtil.ErrNum?USL:maxNum) +groupGap*2));
        if(!t_u)tempList.add(USL);
        if(!t_t)tempList.add(target);
        if(!t_l)tempList.add(LSL);
        double[] xArrays = new double[tempList.size()];//横轴坐标
        for(int i =0;i<xArrays.length;i++){
            xArrays[i]=SpcCalUtil.ZeroFormat(tempList.get(i),2);
        }
//        double[] xArrays = new double[groupSize];//横轴坐标
//        double tempNum = minNum-groupGap;
//        for(int i = 1;i<groupSize-1;i++){
//            xArrays[i]=tempNum+groupGap*i;
//        }
//        xArrays[0] = xArrays[1]-groupGap;
//        xArrays[groupSize-1] = xArrays[groupSize-2]+groupGap;
        int[] frequencyArray = SpcCalUtil.frequency(arrData,xArrays);//正态柱状数量

//        List<Double> newZtArrays = new ArrayList<>();
//        List<Double> newZtAllArrays = new ArrayList<>();
        double[] ztArrays = new double[xArrays.length];//正态分布点值 组内
        double[] ztAllArrays = new double[xArrays.length];//正态分布点值 整体
        for(int i =0;i<xArrays.length;i++){
            if(SpcCalUtil.getNormalValue(xArrays[i],Avage,StDev_zn)!=0&&SpcCalUtil.getNormalValue(xArrays[i],Avage,StDev)!=0) {
                ztArrays[i] = SpcCalUtil.getNormalValue(xArrays[i], Avage, StDev_zn);
                ztAllArrays[i] = SpcCalUtil.getNormalValue(xArrays[i], Avage, StDev);
//                newZtArrays.add(SpcCalUtil.getNormalValue(xArrays[i], Avage, StDev_zn));
//                newZtAllArrays.add(SpcCalUtil.getNormalValue(xArrays[i], Avage, StDev));
            }
        }

//        ztArrays = ArrayUtils.toPrimitive(newZtArrays.toArray(new Double[newZtArrays.size()]));
//        ztAllArrays = ArrayUtils.toPrimitive(newZtAllArrays.toArray(new Double[newZtAllArrays.size()]));
        double UpBdRate_E = SpcCalUtil.ZeroFormat((1-SpcCalUtil.GetP((USL - Avage) / StDev_zn))*1000000,3);
        double LowBdRate_E = SpcCalUtil.ZeroFormat(SpcCalUtil.GetP((LSL - Avage) / StDev_zn)*1000000,3);
        double SumBdRate_E = SpcCalUtil.ZeroFormat(UpBdRate_E + LowBdRate_E,3);

        double UpBdRate_G = SpcCalUtil.ZeroFormat((1-SpcCalUtil.GetP((USL - Avage) / StDev))*1000000,3);
        double LowBdRate_G = SpcCalUtil.ZeroFormat(SpcCalUtil.GetP((LSL - Avage) / StDev)*1000000,3);
        double SumBdRate_G = SpcCalUtil.ZeroFormat(UpBdRate_G + LowBdRate_G,3);

        int gtUCLSize = 0;
        int ltLCLSize = 0;
        if(maxNum> USL){
            for(double i :arrData){
                if(i> USL)gtUCLSize++;
            }
        }
        if(minNum< LSL){
            for(double i :arrData){
                if(i< LSL)ltLCLSize++;
            }
        }
        double UpBdRate = SpcCalUtil.ZeroFormat(gtUCLSize*1000000d/arrData.length,3);
        double LowBdRate = SpcCalUtil.ZeroFormat(ltLCLSize*1000000d/arrData.length,3);
        double SumBdRate = SpcCalUtil.ZeroFormat(UpBdRate + LowBdRate,3);

        //返回
        Map<String,Object> data = new HashMap<String,Object>();
        data.put("ztArrays",ztArrays);
        data.put("frequencyArray",frequencyArray);
        data.put("frequencyMax",SpcCalUtil.maxInt(frequencyArray));
        data.put("xArrays",xArrays);
        data.put("ztAllArrays",ztAllArrays);
        data.put("sampleSize",arrData.length);
        data.put("Avage",SpcCalUtil.ZeroFormat(Avage,3));
        data.put("maxNum",SpcCalUtil.ZeroFormat(maxNum,3));
        data.put("minNum",SpcCalUtil.ZeroFormat(minNum,3));
        data.put("sampleGroupSize",imrFlag?1:sampleSize);

        data.put("USL", USL!=SpcCalUtil.ErrNum?USL:"N/A");
        data.put("LSL", LSL!=SpcCalUtil.ErrNum?LSL:"N/A");
        data.put("target",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":target);
        data.put("StDev_zn",SpcCalUtil.ZeroFormat(StDev_zn,3));
        data.put("StDev",SpcCalUtil.ZeroFormat(StDev,3));
        data.put("StDev_zn3n",SpcCalUtil.ZeroFormat(StDev_zn3n,3));
        data.put("StDev_zn3p",SpcCalUtil.ZeroFormat(StDev_zn3p,3));
        data.put("Cp",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(Cp,3));
        data.put("Cpk",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(SpcCalUtil.cpk(CpkU, CpkL),3));
        data.put("CpkL",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(CpkL,3));
        data.put("CpkU",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(CpkU,3));
        data.put("Pp",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(Pp,3));
        data.put("Ppk",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(SpcCalUtil.cpk(PpkU, PpkL),3));
        data.put("PpkL",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(PpkL,3));
        data.put("PpkU",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(PpkU,3));
        data.put("Ca",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SpcCalUtil.ZeroFormat(Ca,3));
        data.put("UpBdRate_E",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":UpBdRate_E);
        data.put("LowBdRate_E",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":LowBdRate_E);
        data.put("SumBdRate_E",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SumBdRate_E);
        data.put("UpBdRate_G",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":UpBdRate_G);
        data.put("LowBdRate_G",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":LowBdRate_G);
        data.put("SumBdRate_G",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SumBdRate_G);
        data.put("UpBdRate",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":UpBdRate);
        data.put("LowBdRate",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":LowBdRate);
        data.put("SumBdRate",(USL==SpcCalUtil.ErrNum||LSL==SpcCalUtil.ErrNum)?"N/A":SumBdRate);
        return data;
    }

    /**
     * 正态检验
     */
    public Map<String,Object> normalCheck(double[] arrData,double[] avgNums){
        Map<String,Object> data = new HashMap<String,Object>();
        Arrays.sort(arrData);//排序
        double Avage = SpcCalUtil.avage(arrData);//样本平均
        double StDev = SpcCalUtil.stDev(arrData);//整体标准差
        double[] percentArray = new double[]{
                0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,
                0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,
                0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99
            };
        NormalDistribution distribution = new NormalDistribution(Avage,StDev);
        double[] xArray = new double[percentArray.length];//回归线 y轴数据 貌似无用 画出的为曲线 使用z轴
        for(int i=0;i<xArray.length;i++){
            xArray[i] = SpcCalUtil.ZeroFormat(distribution.inverseCumulativeProbability(percentArray[i]),5);
        }
        double[] zArray = new double[percentArray.length];//回归线 z轴数据
        for(int i=0;i<xArray.length;i++) {
            zArray[i] = (distribution.inverseCumulativeProbability(percentArray[i]) - Avage)/StDev;
        }

        double[] sdPredit = new double[arrData.length];//散点估计值 Minitab是以( i-0.3)/(n+0.4)估  i序号 ，n 数组大小
        for(int i=0;i<sdPredit.length;i++){
            sdPredit[i]=SpcCalUtil.ZeroFormat((i+1-0.3)/(arrData.length+0.4)*100d,5);
        }

        double AD = 0d;//AD值  Anderson-Darling 统计量 (A2) A2 度量拟合线（基于所选分布）与非参数步阶函数（基于标绘点）之间的面积。统计量是在分布的尾部施加更大权重的平方距离。如果 Anderson-Darling 值较小，则表明分布与数据拟合得更好
        double P = 0;//P值  P 值是另一个用来报告正态性检验结果的定量度量。
        for(int i=0;i<arrData.length;i++) {
            AD+= (-1-((2d*(i+1)-1)/arrData.length)
                    *
                    (Math.log(distribution.cumulativeProbability(arrData[i]))+
                            Math.log(1-distribution.cumulativeProbability(arrData[arrData.length-i-1]))));
        }
        if(Double.isInfinite(AD)){
        	AD = 0;
        }
        double adn = AD*(1d+0.75d/arrData.length+2.25d/Math.pow(arrData.length,2));
        if(adn<13&&adn>0.6000d){
            P = Math.pow(Math.E,1.2937d - 5.709d * adn + 0.0186d*Math.pow(adn,2));
        }else if(adn<0.600&&adn>0.340){
            P = Math.pow(Math.E,0.9177d - 4.279d * adn-1.38d*Math.pow(adn,2));
        }else if(adn<0.340&&adn>0.200){
            P = 1 - Math.pow(Math.E,-8.318d + 42.796d * adn - 59.938d*Math.pow(adn,2));
        }else if (adn<0.200){
            P = 1 - Math.pow(Math.E,-13.436d + 101.14d * adn - 223.73d*Math.pow(adn,2));
        }

        data.put("Avage",SpcCalUtil.ZeroFormat(Avage,3));
        data.put("StDev",SpcCalUtil.ZeroFormat(StDev,3));
        data.put("xArray",xArray);
        data.put("zArray",zArray);
        data.put("percentArray",percentArray);
        data.put("sdPredit",sdPredit);
        data.put("AD",SpcCalUtil.ZeroFormat(AD,3));
        data.put("P",SpcCalUtil.ZeroFormat(P,3));
        data.put("N",arrData.length);
        data.put("arrData",arrData);
        data.put("minXArray",SpcCalUtil.min(new double[]{SpcCalUtil.min(arrData),SpcCalUtil.min(xArray)}));
        return data;
    }

    /**
     * CPK趋势图 组内
     * @param avgNums 均值
     * @param rNums  极差
     * @param sampleSize 单组样本数
     * @param USL 上限
     * @param LSL 下限
     * @return
     */
    public Map<String,Object> cpkPredit(double[] avgNums,double[] rNums,int sampleSize,double USL,double LSL){
        if(sampleSize==1)sampleSize=2;//样本为1时默认取首个常数
        Map<String,Object> data = new HashMap<String,Object>();
        double[] cpkArray = new double[avgNums.length];
        for(int i=0;i<avgNums.length;i++){
            double cpk = 0d;
            if(rNums[i]!=0) {
                cpk = (USL == SpcCalUtil.ErrNum || LSL == SpcCalUtil.ErrNum) ? 0d :
                        SpcCalUtil.cpk(SpcCalUtil.cpkU(USL, avgNums[i], rNums[i] / SpcCalUtil.D2ConstantNum[sampleSize - 2]),
                                SpcCalUtil.cpkL(LSL, avgNums[i], rNums[i] / SpcCalUtil.D2ConstantNum[sampleSize - 2]));
                cpkArray[i] = SpcCalUtil.ZeroFormat(cpk, 3);
            }
        }
        data.put("cpkArray",cpkArray);
        return data;
    }
    
    /**
     * CPK周期趋势图 整体
     * @param avgNums 均值
     * @param rNums  极差
     * @param sampleSize 单组样本数
     * @param USL 上限
     * @param LSL 下限
     * @return
     */
    public Map<String,Object> cpkCyclePredit(double[] avgNums,double[] rNums,double[] stdNums,int sampleSize,double USL,double LSL){
        if(sampleSize==1)sampleSize=2;//样本为1时默认取首个常数
        Map<String,Object> data = new HashMap<String,Object>();
        double[] cpkArray = new double[avgNums.length];
        for(int i=0;i<avgNums.length;i++){
            double cpk = 0d;
            if(rNums[i]!=0) {
                cpk = (USL == SpcCalUtil.ErrNum || LSL == SpcCalUtil.ErrNum) ? 0d :
                        SpcCalUtil.cpk(SpcCalUtil.cpkU(USL, avgNums[i], stdNums[i]),
                                SpcCalUtil.cpkL(LSL, avgNums[i], stdNums[i]));
                cpkArray[i] = SpcCalUtil.ZeroFormat(cpk, 3);
            }
        }
        data.put("cpkArray",cpkArray);
        return data;
    }
    
    /**
     * @param configId
     * @param type
     * @return
     */
    public Map<String, Object> getCycleSampleData(String configId,String type,String scDate,String cycleHour,Map<String,String> paramMap){
    	String dateFormat = "yyyy-MM-dd";
    	if(type!=null&&type.equals("2")){//按小时
    		dateFormat = "yyyy-MM-dd hh24";
    	}else{//按天
    		dateFormat = "yyyy-MM-dd";
    	}
    	String sqlAdd = "";
    	ArrayList<String> param = new ArrayList<String>();
    	param.add(configId);
    	if(StringUtils.isNotEmpty(scDate)&& scDate.indexOf(" ~ ") > -1){
			String dateFrom = scDate.split(" ~ ")[0];
			String dateTo = scDate.split(" ~ ")[1];
			sqlAdd+= "	and sc.CHECK_DATE >= to_date(?, 'yyyy-MM-dd hh24:mi:ss')"+
					"	and sc.CHECK_DATE <= to_date(?, 'yyyy-MM-dd hh24:mi:ss')";
			param.add(dateFrom);
			param.add(dateTo);
		}
    	if(paramMap!=null&&paramMap.size()>0){
			for(String key:paramMap.keySet()){
				if(StringUtils.isNotEmpty(paramMap.get(key))){
					sqlAdd+= "	and sc."+key+" = ?";
					param.add(paramMap.get(key));
				}
			}
		}
    	String sql = "select to_char(sc.check_date,'"+dateFormat+"') dateStr,avg(sv.value) aval,STDDEV(sv.value) STDVAL," +
    			"(max(sv.value)-min(sv.value)) rval,count(1) DATACOUNT "+
				" FROM Emesq_SPC_SAMPLE_CALC sc, emesq_spc_sample_value sv "+
				" 	where sc.emesq_spc_sample_calc_id=sv.emesq_spc_sample_calc_id "+
				" and sc.emesq_spc_ck_config_id=? "+
				sqlAdd+
				" group by to_char(sc.check_date,'"+dateFormat+"') "+
				" order by to_char(sc.check_date,'"+dateFormat+"')";
    	
//    	System.out.println(sql);
    	List<Map<String, Object>> datas = null;
    	if(type.equals("1")){
    		datas = dao.query(sql, param.toArray());
    	}else{
    		String sql1 = "SELECT to_char(sc.check_date,'yyyy-MM-dd')||' '||trunc((to_number(to_char(sc.check_date,'hh24')))/"+cycleHour+")*"+cycleHour+"||'~'||decode(sign(trunc((to_number(to_char(sc.check_date, 'hh24')) ) / "+cycleHour+") * "+cycleHour+" + "+cycleHour+"-24),1,24,trunc((to_number(to_char(sc.check_date, 'hh24')) ) / "+cycleHour+") * "+cycleHour+" + "+cycleHour+") dateStr,avg(sv.value) aval,STDDEV(sv.value) STDVAL,"+
    				" (max(sv.value)-min(sv.value)) rval,count(1) DATACOUNT "+
    				" FROM Emesq_SPC_SAMPLE_CALC sc, emesq_spc_sample_value sv "+
    				" where sc.emesq_spc_sample_calc_id=sv.emesq_spc_sample_calc_id "+
    				" and sc.emesq_spc_ck_config_id=? "+
    				sqlAdd+
    				" group by to_char(sc.check_date,'yyyy-MM-dd')||' '||trunc((to_number(to_char(sc.check_date,'hh24')))/"+cycleHour+")*"+cycleHour+"||'~'||decode(sign(trunc((to_number(to_char(sc.check_date, 'hh24')) ) / "+cycleHour+") * "+cycleHour+" + "+cycleHour+"-24),1,24,trunc((to_number(to_char(sc.check_date, 'hh24')) ) / "+cycleHour+") * "+cycleHour+" + "+cycleHour+")"+
    				" order by to_char(sc.check_date,'yyyy-MM-dd')||' '||trunc((to_number(to_char(sc.check_date,'hh24')))/"+cycleHour+")*"+cycleHour+"||'~'||decode(sign(trunc((to_number(to_char(sc.check_date, 'hh24')) ) / "+cycleHour+") * "+cycleHour+" + "+cycleHour+"-24),1,24,trunc((to_number(to_char(sc.check_date, 'hh24')) ) / "+cycleHour+") * "+cycleHour+" + "+cycleHour+")";
//    		System.out.println(sql1);
    		datas = dao.query(sql1, param.toArray());
    	}
    	Double[] avgArray = new Double[datas.size()];
    	Double[] rArray = new Double[datas.size()];
    	Double[] stdArray = new Double[datas.size()];
    	int[] countArray = new int[datas.size()];
    	String[] dateArray = new String[datas.size()];
    	if(datas!=null&&datas.size()>0){
    		for(int i=0;i<datas.size();i++){
    			avgArray[i] = Double.parseDouble(datas.get(i).get("AVAL")+"");
    			rArray[i] = Double.parseDouble(datas.get(i).get("RVAL")+"");
    			dateArray[i] = datas.get(i).get("DATESTR")+"";
    			countArray[i] = Integer.parseInt(datas.get(i).get("DATACOUNT")+"");
    			stdArray[i] = Double.parseDouble(datas.get(i).get("STDVAL")+"");
    		}
    	}
    	Map<String, Object> rm = new HashMap<String, Object>();
    	rm.put("avgArray", avgArray);
    	rm.put("avgRArray", rArray);
    	rm.put("dateArray", dateArray);
    	rm.put("stdArray", stdArray);
    	rm.put("countArray", countArray);
    	rm.put("dataSize",avgArray.length);
    	return rm;
    }
}
